rate-limiter-flexible 是 Node.js 常用限流库,支持内存、Redis 等存储。

1. 基础限流

npm install rate-limiter-flexible
const { RateLimiterMemory } = require('rate-limiter-flexible');

const limiter = new RateLimiterMemory({
  points: 5,       // 允许 5 次
  duration: 60,    // 60 秒内
});

async function request(ip) {
  try {
    await limiter.consume(ip);
    console.log('请求通过');
  } catch (rejRes) {
    console.log(`请求过于频繁,请 ${Math.ceil(rejRes.msBeforeNext / 1000)} 秒后重试`);
  }
}

request('127.0.0.1');

2. Express 中使用

const express = require('express');
const { RateLimiterMemory } = require('rate-limiter-flexible');

const app = express();

const limiter = new RateLimiterMemory({
  points: 100,
  duration: 60,
});

app.use(async (req, res, next) => {
  try {
    await limiter.consume(req.ip);
    next();
  } catch (rejRes) {
    res.status(429).json({
      message: '请求过于频繁',
      retryAfter: Math.ceil(rejRes.msBeforeNext / 1000),
    });
  }
});

app.get('/', (req, res) => res.send('OK'));

app.listen(3000);

3. Redis 存储

npm install rate-limiter-flexible ioredis
const Redis = require('ioredis');
const {
  RateLimiterRedis,
} = require('rate-limiter-flexible');

const redisClient = new Redis();

const limiter = new RateLimiterRedis({
  storeClient: redisClient,
  keyPrefix: 'rate-limit',
  points: 10,
  duration: 60,
});

await limiter.consume('user:1001');

4. 登录失败限制

const limiter = new RateLimiterMemory({
  points: 5,
  duration: 900, // 15 分钟
});

async function login(username, ip) {
  const key = `${username}_${ip}`;

  try {
    await limiter.consume(key);
    // 执行登录逻辑
  } catch {
    throw new Error('登录失败次数过多,请稍后再试');
  }
}